package com.alesj.newsfeed.bool.impl;

import java.util.ArrayList;
import java.util.List;

import com.alesj.newsfeed.bool.ConditionCreator;
import com.alesj.newsfeed.bool.Token;
import com.alesj.newsfeed.bool.Tokenizer;
import com.alesj.newsfeed.bool.Condition;

/**
 * @author <a href="mailto:ales.justin@gmail.com">Ales Justin</a>
 */
@SuppressWarnings("unchecked")
public class TokenizerImpl<T> implements Tokenizer {

    private ConditionCreator<T> creator;

    public TokenizerImpl(ConditionCreator<T> creator) {
        this.creator = creator;
    }

    public List<Token> transform(String query) {
        query = query.trim();
        List<Token> tokens = new ArrayList<Token>();
        int pre = 0;
        int space = 0;
        int not = 0;
        StringBuilder writer = new StringBuilder();
        for (int i = 0; i < query.length(); i++) {
            char ch = query.charAt(i);
            if (ch == ' ') {
                space++;
                if (space > 1)
                    continue;
                if (pre == 0) {
                    String token = writer.toString();
                    if (token.trim().length() > 0) {
                        writer.setLength(0);
                        if (isOperator(token))
                            tokens.add(new OperatorToken(token));
                        else {
                            Token<Condition<T>> t = new SimpleToken(creator, token);
                            while (not > 0) {
                                t = new Not<T>(creator, t.value());
                                not--;
                            }
                            tokens.add(t);
                        }
                    }
                    continue;
                }
            } else {
                space = 0;
            }
            if (ch == '!') {
                not++;
            } else {
                writer.append(ch);
            }
            if (ch == '(') {
                pre++;
            }
            if (ch == ')') {
                pre--;
                if (pre == 0) {
                    Token<Condition<T>> token = new PreToken<T>(creator, writer.toString());
                    while(not > 0) {
                        token = new Not<T>(creator, token.value());
                        not--;
                    }
                    tokens.add(token);
                    writer.setLength(0);
                }
            }
        }
        String token = writer.toString().trim();
        if (token.length() > 0) {
            Token<Condition<T>> t = new SimpleToken(creator, token);
            while (not > 0) {
                t = new Not<T>(creator, t.value());
                not--;
            }
            tokens.add(t);
        }
        return tokens;
    }

    protected boolean isOperator(String token) {
        return "AND".equalsIgnoreCase(token) || "OR".equalsIgnoreCase(token);
    }

}
